#include "myudpreceive.h"

MyUdpReceive::MyUdpReceive(const VIDEO_SAVE_CONFIG& config, QObject *parent) : QObject(parent)
{
    m_thread = new QThread;
    m_work = new MyUdpWork(config.bindIP, config.bindNetWorkCard, config.bindPort);
    m_work->moveToThread(m_thread);

    connect(m_thread, &QThread::finished, m_work, &QObject::deleteLater);
    connect(m_work, &MyUdpWork::sigToSaveData, this, &MyUdpReceive::sigToSaveData);
    connect(this, &MyUdpReceive::sigStopProcessing, m_work, &MyUdpWork::stopProcessing);
    connect(m_thread, &QThread::started, m_work, &MyUdpWork::startProcessing);      // 启动数据处理

    //根据视频来源类型，连接不同的初始化
    if(config.bindWay == UNICAST) { //单播初始化方式
       connect(m_thread, &QThread::started, m_work, &MyUdpWork::initSinglecast);
    } else if(config.bindWay == MULTICAST) {  //组播初始化方式
        connect(m_thread, &QThread::started, m_work, &MyUdpWork::initMulticast);
    } else if(config.bindWay == BROADCAST) {  //广播方式接收
        connect(m_thread, &QThread::started, m_work, &MyUdpWork::initBroadcast);
    }

    m_thread->start();
}

MyUdpReceive::~MyUdpReceive()
{
    m_thread->quit();
    m_thread->wait();
    m_thread->deleteLater();
}

void MyUdpReceive::sendStatus(bool status, QString bindIP, quint16 bindPort, QString dstIP, quint16 dstPort)
{
    QUdpSocket *m_controlSocket = new QUdpSocket;
    QByteArray cmd;
    if(status) {
        qDebug() << "camera开始采集";
        cmd.append(static_cast<char>(0x31));       //打开发的31
    } else {
        qDebug() << "camera结束采集";
        cmd.append(static_cast<char>(0x30));       //关闭发的30
    }
    m_controlSocket->bind(QHostAddress(bindIP), bindPort, QUdpSocket::ShareAddress);
    m_controlSocket->writeDatagram(cmd, QHostAddress(dstIP), dstPort);

    delete m_controlSocket;
}

MyUdpWork::MyUdpWork(QString ip, QString netName, quint16 port, QObject *parent) : QObject(parent)
{
    m_ip = ip;
    m_port = port;
    m_netName = netName;
}

void MyUdpWork::initSinglecast()
{
    //qDebug() << "开始初始化udp单播接收线程";
    m_udpReceive = new QUdpSocket(this);

    bool isOK = m_udpReceive->bind(QHostAddress(m_ip), m_port, QUdpSocket::ShareAddress);

    if(isOK == false){
        qDebug()<<QString("单播bind失败%1 %2").arg(m_ip).arg(m_port);
        return;
    }
    qDebug() << "单播成功:" << m_ip << ":" << m_port;
    connect(m_udpReceive, &QUdpSocket::readyRead, this, &MyUdpWork::onReceive);
}

void MyUdpWork::initMulticast()
{
    //qDebug() << "开始初始化udp组播接收线程";
    m_udpReceive = new QUdpSocket(this);

    QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();  //多网卡情况
    QNetworkInterface intf;
    QNetworkInterface intf2;
    bool findNetCard = false; //是否找到网卡
    foreach(intf, list){
        //qInfo() << "inf name:" << intf.humanReadableName() << intf.name();
        if(intf.name().contains(m_netName) == true){
            intf2 = intf;
            findNetCard = true;
            break;
        }
    }
    if(!findNetCard) {
        qDebug() << "没有找到该网卡";
        return;
    }

    //windows上必须绑定AnyIPv4不然就会绑定失败,linux可以绑定具体的组播ip
    bool isOK = m_udpReceive->bind(QHostAddress::AnyIPv4, m_port, QUdpSocket::ShareAddress);

    if(isOK == false){
        qDebug()<<QString("组播bind失败%1 %2").arg(m_ip).arg(m_port)
                << m_udpReceive->localAddress() << m_udpReceive->localPort();
        return;
    }

    isOK = m_udpReceive->joinMulticastGroup(QHostAddress(m_ip), intf2);
    if(isOK == false){
        qDebug()<<QString("组播jion失败%1").arg(m_ip)
                << m_udpReceive->localAddress()<< m_udpReceive->localPort();
        return;
    }
    qDebug() << "组播成功:" << m_ip << ":" << m_port;
    connect(m_udpReceive, &QUdpSocket::readyRead, this, &MyUdpWork::onReceive);
}

void MyUdpWork::initBroadcast()
{
    qDebug() << "开始初始化udp广播接收线程";
    m_udpReceive = new QUdpSocket(this);
    if (m_udpReceive->bind(m_port, QUdpSocket::ShareAddress)) {
        connect(m_udpReceive, &QUdpSocket::readyRead, this, &MyUdpWork::onReceive);
        qDebug() << QString("广播成功，正在监听端口%1").arg(m_port);
    } else {
        qWarning() << "绑定失败!";
    }

    //获取网卡对应的index
    m_netCardIndex = getNetCardIndex(m_netName);
    if(m_netCardIndex == -1) {
        qDebug() << QString("%1网卡的index获取失败").arg(m_netName);
    }
}

int MyUdpWork::getNetCardIndex(QString interfaceName)
{
    QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();
    foreach(const QNetworkInterface &intf, list){
        if(intf.name().contains(interfaceName) == true){
            return intf.index();
        }
    }
    return -1;
}

void MyUdpWork::onReceive()
{
    while (m_udpReceive->hasPendingDatagrams()) {
        //QByteArray datagram;
        //datagram.resize(m_udpReceive->pendingDatagramSize());
        //QHostAddress sender;
        //quint16 senderPort;
        //m_udpReceive->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        QNetworkDatagram datagram = m_udpReceive->receiveDatagram();

//        #ifdef Q_OS_UNIX
//        //如果是广播方式，在linux多网卡情况下，需要获取当前绑定网卡的index，来和收到的网卡的index对比，如果
//        //不一致则舍弃，避免重复接收
//        uint index = datagram.interfaceIndex();

//         if(datagram.interfaceIndex() != static_cast<uint>(m_netCardIndex)) {
//             continue;
//         }
//        #endif

        // 每收到一行数据，帧数加1
        m_frameCount++;

        QString fromIP = datagram.senderAddress().toString().section(":", -1);

        // 检查是否已经超过1秒，计算帧率
        if (m_fpsTimer.elapsed() >= 1000) {
            m_currentFps = m_frameCount * 1000.0 / m_fpsTimer.elapsed();
            qDebug() << fromIP << "udp的接收帧率" << m_currentFps;

            // 重置计时器和计数器
            m_fpsTimer.restart();
            m_frameCount = 0;
        }

        //QString fromIP = sender.toString().section(":", -1);
        //qDebug() << "fromIP:" << fromIP;

        UdpData data;
//        data.ip = sender.toString().section(":", -1);
//        data.port = senderPort;
        data.ip = datagram.senderAddress().toString().section(":", -1);
        data.port = static_cast<quint16>(datagram.senderPort());
        data.data = datagram.data();

        // 尝试入队，如果队列已满则丢弃
        if (!m_dataQueue.enqueue(data)) {
            m_droppedCount++;
            // 每100个丢弃的数据打印一次日志，避免日志刷屏
            if (m_droppedCount % 100 == 0) {
                qWarning() << QString("UDP数据队列已满，已丢弃%1个数据包，当前队列大小:%2/%3")
                              .arg(m_droppedCount)
                              .arg(m_dataQueue.size())
                              .arg(m_dataQueue.maxSize());
                emit sigDataDropped(m_droppedCount);
            }
        }
    }
}

void MyUdpWork::startProcessing()
{
    m_isProcessing = true;
    m_processThread = QThread::create([this]() {
        processData();
    });
    connect(m_processThread, &QThread::finished, m_processThread, &QThread::deleteLater);
    m_processThread->start();
}

void MyUdpWork::stopProcessing()
{
    m_isProcessing = false;
    if (m_processThread) {
        m_processThread->wait();
        m_processThread = nullptr;
    }
    m_dataQueue.clear();  // 清空队列
}

void MyUdpWork::processData()
{
    qDebug() << "开始处理UDP数据，队列最大容量:" << m_dataQueue.maxSize();

    while (m_isProcessing) {
        UdpData data;
        // 等待数据，超时100ms以便检查退出标志
        if (m_dataQueue.dequeue(data, 100)) {
            // 处理数据，转发给存储模块
            emit sigToSaveData(data.ip, data.port, data.data);
        }
    }

    qDebug() << "停止处理UDP数据，总共丢弃的数据包:" << m_droppedCount;
}
